// Copyright 2017 ETH Zurich and University of Bologna.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the “License”); you may not use this file except in
// compliance with the License.  You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/////////////////////////////////////////////////////////
// includes
/////////////////////////////////////////////////////////
#include "mlGemv.h"
#include "bar.h"
#include "utils.h"
#include "bench.h"

/////////////////////////////////////////////////////////
// shared globals
/////////////////////////////////////////////////////////

    float fv0[40] = { 3.72341084F, 2.05988955F, 6.51314163F,
    1.12252951F, 1.66227806F, 0.145220056F, 1.81331241F, 8.89186478F,
    6.15927649F, 2.77416253F, 9.16781521F, 1.34423852F, 6.32391834F, 4.69256F,
    6.8113575F, 0.666300595F, 2.64913654F, 8.20190048F, 8.10120487F, 2.47780204F,
    9.77395058F, 5.73533964F, 3.69658399F, 5.35935F, 4.77251196F, 6.9843235F,
    5.15898F, 9.29441929F, 5.50722837F, 2.04652429F, 2.56426382F, 8.05645275F,
    2.16853786F, 3.84619331F, 1.39571071F, 0.577332199F, 5.79334F, 9.32007885F,
    7.84432697F, 5.62121391F };

  
    float fv1[400] = { 8.89355183F, 4.56787872F, 5.01960611F,
    3.57426763F, 1.93365157F, 9.94315F, 5.33383465F, 6.14486551F, 9.34166431F,
    4.78183651F, 4.15140867F, 5.68520594F, 2.68398905F, 5.06363869F, 2.2263813F,
    0.147600189F, 8.33410835F, 7.29718208F, 7.31444311F, 4.8620224F, 2.03397346F,
    8.89189434F, 4.68149042F, 9.37376404F, 8.01269817F, 8.07543087F, 3.53723168F,
    3.46549726F, 3.52511835F, 3.11159492F, 7.55145121F, 4.44767857F, 7.46242666F,
    8.50842285F, 8.02718067F, 8.06853867F, 7.18519068F, 0.0272353813F,
    8.46274948F, 7.04473972F, 8.52767277F, 5.09189034F, 8.41008854F, 3.39473629F,
    8.17214203F, 5.15605354F, 3.94239545F, 3.30230188F, 4.62144852F, 5.50126028F,
    6.56559038F, 3.88382888F, 4.95562267F, 9.14636517F, 8.59283066F, 1.65165889F,
    4.44284773F, 3.78941035F, 3.91279411F, 5.30239439F, 3.21100593F, 6.33888245F,
    0.953066468F, 7.14185F, 5.55366945F, 5.2259264F, 1.96351099F, 0.638379931F,
    4.90506887F, 4.20652866F, 4.54788446F, 1.41657722F, 8.65172195F, 5.23376179F,
    9.71112347F, 1.65007162F, 3.59117413F, 5.3534708F, 0.403721362F, 3.59708452F,
    2.95918226F, 4.01637125F, 2.12701869F, 4.58302927F, 7.797369F, 9.34188652F,
    9.45202637F, 5.12194777F, 1.32582915F, 1.97581506F, 2.96168804F, 5.22951031F,
    0.514842272F, 1.03592372F, 4.37309456F, 6.85533619F, 8.79378223F,
    9.34466267F, 2.82455492F, 8.83793736F, 7.48141527F, 4.6551466F, 5.2859025F,
    9.51730061F, 9.81279659F, 5.62915421F, 1.33510506F, 0.474726826F,
    9.73775768F, 3.26722813F, 6.81313181F, 9.91118431F, 6.2909565F, 1.63100421F,
    6.34688139F, 2.38592482F, 7.97391891F, 9.66444874F, 5.51800203F, 8.03939056F,
    5.26805449F, 0.632442176F, 6.54882908F, 7.71907377F, 5.20940113F,
    4.06845045F, 6.72902107F, 6.20146179F, 6.28422976F, 9.06049347F, 9.26755333F,
    6.31395149F, 6.99516344F, 2.20040607F, 3.20653486F, 3.57118654F, 5.19455671F,
    1.94657719F, 8.35009384F, 8.43649483F, 1.66590858F, 4.06445694F, 5.8533206F,
    1.58943772F, 0.613050938F, 4.56940794F, 7.88240337F, 8.42094326F,
    7.04898071F, 0.687213957F, 9.38457203F, 7.70664787F, 2.07973909F,
    7.94114923F, 9.92709255F, 0.561131179F, 1.92694902F, 8.65584087F,
    3.04399323F, 2.08458F, 3.36043787F, 6.96889305F, 2.83444262F, 3.45543647F,
    2.19631791F, 6.92904472F, 9.10691166F, 6.97813654F, 4.38564F, 1.73158181F,
    2.76542974F, 9.60164452F, 2.71240878F, 8.2477026F, 3.63456392F, 3.64597964F,
    9.0710659F, 7.55235386F, 4.63807774F, 1.52804577F, 3.1937747F, 3.25456285F,
    4.43187714F, 0.231135175F, 8.43322372F, 4.80349398F, 2.10156488F,
    1.51781344F, 1.43716979F, 5.72974491F, 1.62514722F, 8.06296062F, 1.11817336F,
    6.26916456F, 6.75151443F, 1.68777883F, 0.269986421F, 7.00556183F,
    1.38582611F, 9.3600769F, 4.85354185F, 0.819970191F, 9.2824707F, 8.89334202F,
    3.9675386F, 8.71131897F, 1.32072401F, 2.12184834F, 2.33924055F, 9.96535873F,
    7.06366062F, 9.44258F, 6.12556744F, 7.61981916F, 2.08140206F, 0.675686657F,
    0.51997304F, 5.4449892F, 3.80034137F, 4.55695343F, 1.98929226F, 5.32173634F,
    8.3203907F, 9.43984604F, 8.91404F, 2.22370648F, 9.61286163F, 1.84532678F,
    9.77004623F, 7.76385355F, 9.08932209F, 5.86040592F, 6.61322355F, 1.06963074F,
    2.40745831F, 0.621600866F, 5.36141634F, 7.38342905F, 0.18428871F,
    4.56586361F, 0.132126406F, 1.01691949F, 5.37265301F, 5.61571074F, 9.73611F,
    9.83595371F, 3.46664262F, 1.1433605F, 1.42728627F, 3.78482771F, 2.2256012F,
    4.09024F, 8.63858604F, 0.0709085763F, 8.30439377F, 2.41167521F, 9.21803093F,
    1.03441453F, 3.66076255F, 3.96449089F, 0.180362284F, 8.98919392F,
    3.36497569F, 9.9118042F, 2.99364591F, 7.40250969F, 9.44812584F, 5.94236422F,
    7.13212633F, 3.5057745F, 9.5456F, 0.869502127F, 4.69311047F, 5.28086185F,
    9.61512375F, 8.07825184F, 7.20355129F, 5.21836042F, 6.00257F, 0.594679594F,
    1.45142186F, 4.32936239F, 1.26345515F, 8.53395557F, 2.35414219F, 5.92928886F,
    6.59487677F, 9.48331356F, 0.034913715F, 2.03494549F, 2.44284678F,
    2.47186375F, 6.20175743F, 2.85174847F, 3.19201946F, 4.34211826F, 5.04081917F,
    7.28939438F, 8.55611801F, 1.49843264F, 1.386796F, 1.82783306F, 9.14081192F,
    7.80997086F, 4.68266344F, 2.10241413F, 5.73643589F, 8.38018894F, 8.60306549F,
    1.89570379F, 1.57764232F, 2.04463959F, 7.14660883F, 1.60526013F, 3.3099916F,
    6.12731647F, 1.93052459F, 4.64242506F, 5.26544285F, 9.01889706F, 8.91478157F,
    2.70034981F, 6.75611067F, 7.26871F, 6.05265951F, 1.6248256F, 4.65173388F,
    3.15073848F, 5.0563879F, 9.41321087F, 2.57409954F, 3.08112621F, 5.78834152F,
    8.22133064F, 4.91149616F, 4.8047843F, 3.40375638F, 5.1064558F, 2.37319517F,
    5.73145533F, 2.61027241F, 3.23468F, 1.7235055F, 5.95532799F, 3.16561556F,
    7.17146349F, 1.4843626F, 5.73935223F, 0.109899975F, 4.05686665F, 2.00048304F,
    9.3144865F, 4.67858124F, 4.89148092F, 9.18386173F, 9.09692669F, 8.02498817F,
    1.5047555F, 4.27849F, 9.1459322F, 6.01375341F, 1.87017262F, 0.411061376F,
    3.75596285F, 3.72159791F, 7.82693815F, 5.92564F, 1.48865986F, 1.78215814F,
    1.22855175F, 2.46720695F, 1.65368629F, 9.36774063F, 8.1400547F, 4.9121933F,
    9.9825449F, 2.33448339F, 6.49357224F, 9.51950264F, 7.59622335F, 4.62405157F,
    2.8869679F, 6.04804754F, 6.70537281F, 5.58624411F, 3.58296919F, 0.10297852F,
    1.37817633F, 5.91864347F, 6.19787741F, 6.3463006F, 2.41259861F, 0.426108032F,
    1.41855764F, 5.81369F, 2.02117443F, 6.54868555F, 7.27920961F, 0.115743004F,
    8.59063339F };

    float fv2[40] = { 0.758510828F, 2.35631561F, 1.30502653F,
    9.31223774F, 2.64225149F, 4.62035418F, 8.53274632F, 2.37871552F, 3.20525694F,
    6.57087898F, 9.76775265F, 4.00537634F, 6.0920825F, 2.51103F, 3.18911743F,
    4.56687593F, 5.60542965F, 2.32669449F, 5.53912735F, 8.9172287F, 5.34343386F,
    3.77733779F, 5.65509796F, 8.94718742F, 8.96546F, 7.4111619F, 5.85733318F,
    5.00474834F, 5.42933226F, 2.44653893F, 6.77971411F, 6.875144F, 3.9568727F,
    4.06102037F, 7.89398336F, 9.27550125F, 9.85645866F, 3.10645771F, 2.69238782F,
    1.88966703F };

    float fv3[4] = { 6.01999283F, 3.66133881F, 8.7223053F,
    4.38774824F };

    float fv4[16] = { 2009.4032F, 2009.36292F, 1825.95581F,
    1825.91919F, 2710.64697F, 2710.59277F, 442.488892F, 442.480042F, 3426.41602F,
    3426.34766F, 4019.78638F, 4019.70581F, 2453.13F, 2453.08105F, 2835.13208F,
    2835.07544F };


/////////////////////////////////////////////////////////
// subfunctions
/////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////
// main testing function 
/////////////////////////////////////////////////////////
int main(int argc, const char * const argv[])
{
  (void)argc;
  (void)argv;

  int coreid;
  int it;

  boolean_T pass;
  boolean_T flag;
  float y[10];
  int ix;
  float b_y;
  int b_k;
  float xbar;
  float r;
  float c_y;
  float check[2];
  float golden[4];



  /////////////////////////////////////////////////////////
  // main test loop 
  // each core loops over a kernel instance
  /////////////////////////////////////////////////////////
  coreid = get_core_id();

  printf("starting %d kernel iterations... (coreid = %d)\n",KERNEL_ITS,coreid);

  if (coreid>3)
    coreid=coreid-4;

  synch_barrier();

  perf_begin();

  for(it = 0; it < getKernelIts(); it++)
  {
    // matlab kernel
    for (ix = 0; ix < 10; ix++) {
      b_y = 0.0F;
      for (b_k = 0; b_k < 10; b_k++) {
        b_y += fv1[(ix + 10 * b_k) + 100 * coreid] * fv0[b_k + 10 * coreid];
      }
      y[ix] = b_y + fv3[coreid] * fv2[ix + 10 * coreid];
    }
  }

  synch_barrier();

  perf_end();

  synch_barrier();

  /////////////////////////////////////////////////////////
  // check results
  /////////////////////////////////////////////////////////

  b_y = y[0];
  ix = 0;
  xbar = y[0];
  for (b_k = 0; b_k < 9; b_k++) {
    b_y += y[b_k + 1];
    ix++;
    xbar += y[ix];
  }

  xbar *= 1.0F/10.0F;
  ix = 0;
  r = y[0] - xbar;
  c_y = r * r;
  for (b_k = 0; b_k < 9; b_k++) {
    ix++;
    r = y[ix] - xbar;
    c_y += r * r;
  }

  c_y *= 1.0F/9.0F;
  check[0] = b_y;
  check[1] = c_y;
  pass = true;
  for (ix = 0; ix < 2; ix++) {
    for (b_k = 0; b_k < 2; b_k++) {
      golden[b_k + (ix << 1)] = fv4[(b_k + (ix << 1)) + (coreid << 2)];
    }
    flag = true;
    flag = pass && (check[ix] <= golden[ix << 1]);
    flag = pass && (check[ix] >= golden[1 + (ix << 1)]);
    printErrors(!flag, ix, check[ix], golden[ix<<1], golden[1+(ix<<1)]);
    pass = pass && flag;
  }
  flagPassFail(pass, get_core_id());


/////////////////////////////////////////////////////////
// synchronize and exit
/////////////////////////////////////////////////////////

  return !pass;
}

